blob: cfc5840186c0e2fb680bff1babcb46a7380413fd (
plain) (
tree)
|
|
<script lang="ts">
import { beforeNavigate } from '$app/navigation';
import { updateComics } from '$gql/Mutations';
import { comicQuery } from '$gql/Queries';
import { comicEquals } from '$gql/Utils';
import { UpdateMode, type FullComicFragment, type UpdateComicInput } from '$gql/graphql';
import { initReaderContext } from '$lib/Reader';
import { initScraperContext } from '$lib/Scraper';
import { initSelectionContext } from '$lib/Selection';
import { setTabContext } from '$lib/Tabs';
import { toastFinally } from '$lib/Toasts';
import { preventOnPending } from '$lib/Utils';
import BookmarkButton from '$lib/components/BookmarkButton.svelte';
import Guard from '$lib/components/Guard.svelte';
import Head from '$lib/components/Head.svelte';
import OrganizedButton from '$lib/components/OrganizedButton.svelte';
import RemovePageButton from '$lib/components/RemovePageButton.svelte';
import SubmitButton from '$lib/components/SubmitButton.svelte';
import Titlebar from '$lib/components/Titlebar.svelte';
import Grid from '$lib/containers/Grid.svelte';
import ComicForm from '$lib/forms/ComicForm.svelte';
import Gallery from '$lib/gallery/Gallery.svelte';
import PageView from '$lib/reader/PageView.svelte';
import Reader from '$lib/reader/Reader.svelte';
import ComicScrapeForm from '$lib/scraper/ComicScrapeForm.svelte';
import ComicDelete from '$lib/tabs/ComicDelete.svelte';
import ComicDetails from '$lib/tabs/ComicDetails.svelte';
import Tab from '$lib/tabs/Tab.svelte';
import Tabs from '$lib/tabs/Tabs.svelte';
import SelectionControls from '$lib/toolbar/SelectionControls.svelte';
import { getContextClient } from '@urql/svelte';
import type { PageData } from './$types';
const client = getContextClient();
const reader = initReaderContext();
const selection = initSelectionContext();
const scraper = initScraperContext();
const tabContext = setTabContext({
tabs: {
details: { title: 'Details' },
edit: { title: 'Edit' },
scrape: { title: 'Scrape' },
deletion: { title: 'Delete' }
},
current: 'details'
});
export let data: PageData;
$: result = comicQuery(client, { id: data.id });
let comic: FullComicFragment;
let original: Readonly<FullComicFragment>;
let updatePartial = false;
$: $result, update();
$: pending = !comicEquals(comic, original);
$: $tabContext.tabs.edit.badge = pending;
function update() {
if (!$result.stale && $result.data?.comic.__typename === 'FullComic') {
original = $result.data.comic;
if (updatePartial) {
comic.pages = structuredClone(original.pages);
comic.favourite = original.favourite;
comic.bookmarked = original.bookmarked;
comic.organized = original.organized;
comic.updatedAt = original.updatedAt;
updatePartial = false;
} else {
comic = structuredClone(original);
}
$reader.pages = original.pages;
$selection.view = comic.pages;
$scraper.selector = undefined;
}
}
function toggle(field: keyof Omit<UpdateComicInput, 'cover'>) {
updateComics(client, { ids: comic.id, input: { [field]: !comic[field] } })
.then(() => (updatePartial = true))
.catch(toastFinally);
}
function updateComic(event: CustomEvent<UpdateComicInput>) {
updateComics(client, { ids: comic.id, input: event.detail }).catch(toastFinally);
}
function updateCover(event: CustomEvent<number>) {
updateComics(client, { ids: comic.id, input: { cover: { id: event.detail } } })
.then(() => (updatePartial = true))
.catch(toastFinally);
}
function removePages() {
updateComics(client, {
ids: comic.id,
input: { pages: { ids: $selection.ids, options: { mode: UpdateMode.Remove } } }
})
.then(() => {
updatePartial = true;
$selection = $selection.clear();
})
.catch(toastFinally);
}
beforeNavigate((navigation) => preventOnPending(navigation, pending));
</script>
<Head section="Comic" title={original?.title} />
{#if comic}
<Grid>
<header>
<Titlebar
title={original.title}
subtitle={original.originalTitle}
bind:favourite={comic.favourite}
on:favourite={() => toggle('favourite')}
/>
</header>
<aside>
<Tabs>
<Tab id="details">
<ComicDetails comic={original} />
</Tab>
<Tab id="edit">
<div class="flex flex-col gap-4">
<div class="flex gap-2 text-sm">
<SelectionControls page>
<RemovePageButton on:click={removePages} />
</SelectionControls>
<div class="grow" />
<BookmarkButton bookmarked={comic.bookmarked} on:click={() => toggle('bookmarked')} />
<OrganizedButton organized={comic.organized} on:click={() => toggle('organized')} />
</div>
<ComicForm bind:comic on:submit={updateComic}>
<div class="flex gap-2">
<div class="grow" />
<SubmitButton active={pending} />
</div>
</ComicForm>
</div>
</Tab>
<Tab id="scrape">
<ComicScrapeForm {comic} />
</Tab>
<Tab id="deletion">
<ComicDelete {comic} />
</Tab>
</Tabs>
</aside>
<main class="overflow-auto">
<Gallery
pages={comic.pages}
on:open={(e) => ($reader = $reader.open(e.detail))}
on:cover={updateCover}
/>
</main>
</Grid>
<Reader>
<PageView layout={comic.layout} direction={comic.direction} />
<svelte:fragment slot="sidebar">
<ComicForm bind:comic on:submit={updateComic}>
<div class="flex justify-end gap-2">
<SubmitButton active={pending} />
</div>
</ComicForm>
</svelte:fragment>
</Reader>
{:else}
<Guard {result} />
{/if}
|